package com.jerei.plugin.service.impl;

import com.chenlb.mmseg4j.analysis.ComplexAnalyzer;
import com.jerei.plugin.api.ILuceneService;
import com.jerei.utils.UtilsCommon;
import com.jerei.utils.lucene.PageBeanForLucene;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.springframework.stereotype.Service;
import ro.fortsoft.pf4j.Extension;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by sunfeihu on 2016/12/28.
 */
@Extension
@Service
public class LuceneServiceImpl implements ILuceneService {

    private File getBaseFolder(String category) {
        String folderStr = this.getClass().getClassLoader().getResource("").getPath();
        folderStr = folderStr + File.separator + "index" + File.separator + category;
        File folder = new File(folderStr);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        return folder;
    }

    @Override
    public void index(String category, List<Map<String, Object>> datas) {
        IndexWriter indexWriter = null;
        try {
            Directory directory = FSDirectory.open(this.getBaseFolder(category));
            Analyzer analyzer = new ComplexAnalyzer();
            IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_45, analyzer);
            indexWriter = new IndexWriter(directory, indexWriterConfig);
            indexWriter.deleteAll();
            Document document = null;
            for (Map<String, Object> data : datas) {
                document = new Document();
                for (String key : data.keySet()) {
                    document.add(new Field(key, UtilsCommon.getString(data.get(key)), TextField.TYPE_STORED));
                }
                indexWriter.addDocument(document);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (indexWriter != null) {
                    indexWriter.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private ScoreDoc getLastScoreDoc(int pageIndex, int pageSize, Query query, IndexSearcher searcher) throws IOException {
        if (pageIndex == 1) return null;//如果是第一页就返回空
        int num = pageSize * (pageIndex - 1);//获取上一页的最后数量
        TopDocs tds = searcher.search(query, num);
        return tds.scoreDocs[num - 1];
    }

    @Override
    public PageBeanForLucene search(PageBeanForLucene pageBeanForLucene) {
        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
        DirectoryReader directoryReader = null;
        try {
            Directory directory = FSDirectory.open(this.getBaseFolder(pageBeanForLucene.getCategory()));
            directoryReader = DirectoryReader.open(directory);
            IndexSearcher indexSearcher = new IndexSearcher(directoryReader);
            Analyzer analyzer = new ComplexAnalyzer();
            BooleanClause.Occur[] clauses = new BooleanClause.Occur[pageBeanForLucene.getFields().length];
            for (int i = 0; i < pageBeanForLucene.getFields().length; i++) {
                clauses[i] = BooleanClause.Occur.SHOULD;
            }
            Query query = MultiFieldQueryParser.parse(Version.LUCENE_45, pageBeanForLucene.getKeywords(), pageBeanForLucene.getFields(), clauses, analyzer);
            ScoreDoc lastSd = getLastScoreDoc(pageBeanForLucene.getNowPage(), pageBeanForLucene.getPageSize(), query, indexSearcher);
            TopDocs tds = indexSearcher.searchAfter(lastSd, query, pageBeanForLucene.getPageSize());
            Map<String, String> map = null;
            Document doc = null;
            for (ScoreDoc sd : tds.scoreDocs) {
                doc = indexSearcher.doc(sd.doc);
                map = new HashMap<String, String>();
                for (IndexableField field : doc.getFields()) {
                    map.put(field.name(), field.stringValue());
                }
                list.add(map);
            }
            pageBeanForLucene.setResultList(list);
            pageBeanForLucene.setTotalRows(tds.totalHits);
            pageBeanForLucene.setTotalPages(((Double) Math.ceil(tds.totalHits / pageBeanForLucene.getPageSize())).intValue());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (directoryReader != null) {
                    directoryReader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return pageBeanForLucene;
    }
}